from celery import shared_task
import pandas as pd
import logging
from io import BytesIO
from .models import Customer, Order, Product
from apps.UMM.models import User
from django.db import transaction
import os

logger = logging.getLogger(__name__)

@shared_task
def import_customers_task(file_path, delete_after=True):
    """
    客户数据导入异步任务
    :param file_path: 上传的Excel文件临时保存路径
    :param delete_after: 处理完后是否删除文件
    :return: 导入结果统计
    """
    try:
        logger.info(f"开始导入客户数据，文件路径: {file_path}")
        
        # 确认文件存在
        if not os.path.exists(file_path):
            error_msg = f"文件不存在: {file_path}"
            logger.error(error_msg)
            return {
                'success': False, 
                'message': error_msg
            }
        
        # 确认文件大小
        file_size = os.path.getsize(file_path)
        logger.info(f"文件大小: {file_size} 字节")
        if file_size == 0:
            error_msg = "文件为空"
            logger.error(error_msg)
            return {
                'success': False, 
                'message': error_msg
            }
        
        # 读取Excel文件
        try:
            logger.info("开始读取Excel文件...")
            df = pd.read_excel(file_path)
            logger.info(f"成功读取Excel文件，包含 {len(df)} 行数据和以下列: {', '.join(df.columns)}")
        except Exception as excel_error:
            error_msg = f"读取Excel文件失败: {str(excel_error)}"
            logger.error(error_msg)
            return {
                'success': False, 
                'message': error_msg
            }
        
        # 验证必要的列是否存在
        if '客户名称*' not in df.columns:
            error_msg = '导入文件缺少必要的列：客户名称*'
            logger.error(error_msg)
            return {
                'success': False, 
                'message': error_msg
            }
        
        # 获取总行数用于计算进度
        total_rows = len(df)
        logger.info(f"开始处理 {total_rows} 条数据")
        
        # 如果数据量太大，采用分批处理策略
        batch_size = 1000  # 增加批处理大小到1000条记录
        
        # 重命名列以匹配模型字段
        column_mapping = {
            '客户名称*': 'customer_name',
            '客户来源': 'customer_source',
            '手机号码': 'phone_number'
        }
        df = df.rename(columns=column_mapping)
        
        # 转换客户来源为数字
        source_mapping = {
            'Newbe工作室': 0,
            '纽币德信息科技': 1,
            '官方网站': 2,
            '其它': 3
        }
        
        # 替换客户来源
        if 'customer_source' in df.columns:
            df['customer_source'] = df['customer_source'].map(lambda x: source_mapping.get(x, 3))
        else:
            # 如果客户来源列不存在，添加默认值
            df['customer_source'] = 3
        
        # 验证客户名称是否为空
        if df['customer_name'].isnull().any():
            return {
                'success': False, 
                'message': '客户名称不能为空'
            }
        
        # 处理导入数据中的重复客户名称
        duplicate_names = df[df.duplicated('customer_name', keep='first')]['customer_name'].unique()
        duplicate_count = 0
        if len(duplicate_names) > 0:
            # 记录重复的客户名称
            duplicates_str = ', '.join(duplicate_names)
            logger.info(f'导入数据中存在重复的客户名称，已自动保留首次出现的记录: {duplicates_str}')
            
            # 保留重复客户名称的第一条记录，删除其余记录
            df = df.drop_duplicates(subset=['customer_name'], keep='first')
            duplicate_count = len(duplicate_names)
        
        # 收集已存在的客户名称
        existing_names = []
        
        # 预先检查数据库中已存在的客户名称以提高性能
        all_customer_names = set(Customer.objects.values_list('customer_name', flat=True))
        
        # 开始导入数据
        imported_count = 0
        skipped_count = 0
        errors = []
        
        # 分批处理数据以提高性能
        for batch_start in range(0, total_rows, batch_size):
            batch_end = min(batch_start + batch_size, total_rows)
            batch_df = df.iloc[batch_start:batch_end]
            
            # 收集需要创建的新客户
            new_customers = []
            
            with transaction.atomic():  # 使用事务确保批量操作的原子性
                for index, row in batch_df.iterrows():
                    customer_name = row['customer_name']
                    
                    # 检查客户是否已存在
                    if customer_name in all_customer_names:
                        # 客户已存在，记录并跳过
                        existing_names.append(customer_name)
                        skipped_count += 1
                        continue
                    
                    # 客户不存在，准备创建新记录
                    data = {
                        'customer_name': customer_name,
                        'customer_source': row['customer_source'],
                    }
                    
                    # 如果手机号码列存在且不为空
                    if 'phone_number' in row and pd.notna(row['phone_number']):
                        data['phone_number'] = str(row['phone_number'])
                    
                    try:
                        # 将新客户添加到批量创建列表
                        new_customers.append(Customer(**data))
                        # 将新创建的客户添加到缓存中，避免重复检查数据库
                        all_customer_names.add(customer_name)
                    except Exception as e:
                        # 记录创建失败的客户
                        errors.append(f"行 {index+2}: {customer_name} - {str(e)}")
                        logger.error(f"导入客户 {customer_name} 失败: {str(e)}")
                
                # 批量创建新客户
                if new_customers:
                    Customer.objects.bulk_create(new_customers)
                    imported_count += len(new_customers)
                    logger.info(f"批量创建了 {len(new_customers)} 个新客户")
        
        # 清理临时文件
        if delete_after and os.path.exists(file_path):
            os.remove(file_path)
            logger.info(f"清理临时文件: {file_path}")
        
        # 构建返回消息
        message = f'成功导入{imported_count}条客户记录'
        if skipped_count > 0:
            message += f'，跳过{skipped_count}条已存在的客户记录'
        
        if duplicate_count > 0:
            message += f'，跳过{duplicate_count}条重复的客户记录'
        
        if errors:
            message += f'，{len(errors)}条记录导入失败'
        
        return {
            'success': True,
            'message': message,
            'imported_count': imported_count,
            'skipped_count': skipped_count,
            'duplicate_count': duplicate_count,
            'skipped_names': existing_names,
            'errors': errors if len(errors) <= 20 else errors[:20] + [f"...还有{len(errors)-20}条错误未显示"],
            'total_processed': imported_count + skipped_count,
            'total_rows': total_rows
        }
    except Exception as e:
        logger.error(f"导入客户数据出错: {str(e)}")
        import traceback
        error_details = traceback.format_exc()
        logger.error(f"详细错误: {error_details}")
        
        # 清理临时文件
        if delete_after and os.path.exists(file_path):
            os.remove(file_path)
        
        return {
            'success': False, 
            'message': f'导入出错: {str(e)}', 
            'details': error_details
        }

@shared_task
def import_orders_task(file_path, delete_after=True):
    """
    订单数据导入异步任务
    :param file_path: 上传的Excel文件临时保存路径
    :param delete_after: 处理完后是否删除文件
    :return: 导入结果统计
    """
    try:
        logger.info(f"开始异步导入订单数据，文件路径: {file_path}")
        
        # 读取Excel文件
        df = pd.read_excel(file_path)
        
        # 验证必要的列是否存在
        required_columns = ['订单号', '客户名称', '产品名称', '订单金额', '购买年限', '订单状态', '下单日期', '订单来源']
        missing_columns = [col for col in required_columns if col not in df.columns]
        
        if missing_columns:
            logger.error(f"缺少必要的列: {', '.join(missing_columns)}")
            return {
                'success': False, 
                'message': f"缺少必要的列: {', '.join(missing_columns)}"
            }
        
        # 用于存储导入结果
        import_count = 0
        error_rows = []
        
        # 获取所有客户名称和产品名称的映射，减少数据库查询
        customers_dict = {c.customer_name: c for c in Customer.objects.all()}
        products_dict = {p.product_name: p for p in Product.objects.all()}
        if '激活人' in df.columns:
            users_dict = {u.nickname: u for u in User.objects.all()}
        else:
            users_dict = {}
        
        # 映射字段
        order_source_map = {'Newbe工作室': 0, '纽币德信息科技': 1, '官方网站': 2, '其它': 3}
        purchase_years_map = {'永久': 0, '1年': 1, '2年': 2, '3年': 3, '4年': 4, '5年': 5}
        order_status_map = {'未激活': 0, '已激活': 1, '临时IP激活': 2}
        invoice_map = {'是': 1, '否': 0}
        double_coms_map = {'是': 1, '否': 0}
        
        # 批量处理
        batch_size = 200
        total_rows = len(df)
        
        # 准备批量创建
        new_orders = []
        
        for start_idx in range(0, total_rows, batch_size):
            end_idx = min(start_idx + batch_size, total_rows)
            batch_df = df.iloc[start_idx:end_idx]
            
            with transaction.atomic():
                for index, row in batch_df.iterrows():
                    try:
                        line_num = index + 2  # Excel行号从2开始（1是表头）
                        logger.info(f"处理第 {line_num} 行数据")
                        
                        # 验证必填字段
                        missing_fields = []
                        for field in ['订单号', '客户名称', '产品名称', '订单金额', '下单日期']:
                            if pd.isna(row.get(field, None)):
                                missing_fields.append(field)
                        
                        if missing_fields:
                            error_msg = f"第{line_num}行: 缺少必填字段: {', '.join(missing_fields)}"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        
                        # 检查客户是否存在
                        customer_name = row['客户名称']
                        logger.info(f"查找客户: {customer_name}")
                        
                        if customer_name not in customers_dict:
                            error_msg = f"第{line_num}行: 客户 '{customer_name}' 不存在"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        
                        customer = customers_dict[customer_name]
                        
                        # 检查产品是否存在
                        product_name = row['产品名称']
                        logger.info(f"查找产品: {product_name}")
                        
                        if product_name not in products_dict:
                            error_msg = f"第{line_num}行: 产品 '{product_name}' 不存在"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        
                        product = products_dict[product_name]
                        
                        # 处理激活人
                        nickname_instance = None
                        if '激活人' in row and pd.notna(row['激活人']):
                            nickname = row['激活人']
                            logger.info(f"查找激活人: {nickname}")
                            
                            if nickname not in users_dict:
                                error_msg = f"第{line_num}行: 激活人 '{nickname}' 不存在"
                                logger.error(error_msg)
                                error_rows.append(error_msg)
                                continue
                            
                            nickname_instance = users_dict[nickname]
                        
                        # 处理枚举值
                        # 订单来源
                        order_source_str = row['订单来源']
                        if pd.isna(order_source_str) or order_source_str not in order_source_map:
                            error_msg = f"第{line_num}行: 无效的订单来源 '{order_source_str}'，有效值为: Newbe工作室, 纽币德信息科技, 官方网站, 其它"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        order_source = order_source_map.get(order_source_str)
                        
                        # 购买年限
                        purchase_years_str = row['购买年限']
                        if pd.isna(purchase_years_str) or purchase_years_str not in purchase_years_map:
                            error_msg = f"第{line_num}行: 无效的购买年限 '{purchase_years_str}'，有效值为: 永久, 1年, 2年, 3年, 4年, 5年"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        purchase_years = purchase_years_map.get(purchase_years_str)
                        
                        # 订单状态
                        order_status_str = row['订单状态']
                        if pd.isna(order_status_str) or order_status_str not in order_status_map:
                            error_msg = f"第{line_num}行: 无效的订单状态 '{order_status_str}'，有效值为: 未激活, 已激活, 临时IP激活"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        order_status = order_status_map.get(order_status_str)
                        
                        # 是否已开票
                        invoice_str = row.get('是否已开票', '否')
                        is_invoice = 0
                        if pd.notna(invoice_str):
                            if invoice_str not in invoice_map:
                                error_msg = f"第{line_num}行: 无效的开票状态 '{invoice_str}'，有效值为: 是, 否"
                                logger.error(error_msg)
                                error_rows.append(error_msg)
                                continue
                            is_invoice = invoice_map.get(invoice_str)
                        
                        # 是否双倍提成
                        double_coms_str = row.get('是否双倍提成', '否')
                        is_double_coms = 0
                        if pd.notna(double_coms_str):
                            if double_coms_str not in double_coms_map:
                                error_msg = f"第{line_num}行: 无效的双倍提成状态 '{double_coms_str}'，有效值为: 是, 否"
                                logger.error(error_msg)
                                error_rows.append(error_msg)
                                continue
                            is_double_coms = double_coms_map.get(double_coms_str)
                        
                        # 处理订单日期和激活日期
                        # 处理下单日期
                        order_date = row['下单日期']
                        if pd.isna(order_date):
                            error_msg = f"第{line_num}行: 下单日期不能为空"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        
                        logger.info(f"下单日期值类型: {type(order_date)}")
                        try:
                            import datetime
                            if isinstance(order_date, str):
                                order_date = datetime.datetime.strptime(order_date, '%Y-%m-%d').date()
                            elif isinstance(order_date, datetime.datetime):
                                order_date = order_date.date()
                            logger.info(f"处理后的下单日期: {order_date}")
                        except Exception as e:
                            error_msg = f"第{line_num}行: 下单日期格式错误 '{order_date}' - {str(e)}"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        
                        # 处理激活日期
                        activation_date = None
                        if '激活日期' in row and pd.notna(row['激活日期']):
                            activation_date_raw = row['激活日期']
                            try:
                                import datetime
                                if isinstance(activation_date_raw, str):
                                    activation_date = datetime.datetime.strptime(activation_date_raw, '%Y-%m-%d').date()
                                elif isinstance(activation_date_raw, datetime.datetime):
                                    activation_date = activation_date_raw.date()
                                logger.info(f"处理后的激活日期: {activation_date}")
                            except Exception as e:
                                error_msg = f"第{line_num}行: 激活日期格式错误 '{activation_date_raw}' - {str(e)}"
                                logger.error(error_msg)
                                error_rows.append(error_msg)
                                continue
                        
                        # 处理订单金额
                        try:
                            order_amount = float(row['订单金额'])
                            if order_amount <= 0:
                                error_msg = f"第{line_num}行: 订单金额必须大于0"
                                logger.error(error_msg)
                                error_rows.append(error_msg)
                                continue
                        except ValueError:
                            error_msg = f"第{line_num}行: 订单金额必须是有效的数字"
                            logger.error(error_msg)
                            error_rows.append(error_msg)
                            continue
                        
                        # 计算提成
                        commission = None
                        if order_status == 1 or order_status == 2:  # 已激活 或 临时IP激活
                            commission_rate = product.commission_category.commission_ratio
                            commission = float(order_amount) * float(commission_rate)
                            if is_double_coms == 1:  # 双倍提成
                                commission *= 2
                        
                        # 创建订单数据
                        order_data = {
                            'order_source': order_source,
                            'order_number': row['订单号'],
                            'customer_name': customer,
                            'order_date': order_date,
                            'product_name': product,
                            'order_amount': order_amount,
                            'purchase_years': purchase_years,
                            'order_status': order_status,
                            'authorized_domain': row.get('授权域名', '') if pd.notna(row.get('授权域名', None)) else None,
                            'activation_date': activation_date,
                            'nickname': nickname_instance,
                            'authorization_code': row.get('授权码', '') if pd.notna(row.get('授权码', None)) else '',
                            'order_remarks': row.get('订单备注') if pd.notna(row.get('订单备注', None)) else None,
                            'is_invoice': is_invoice,
                            'is_double_coms': is_double_coms,
                            'commission': commission
                        }
                        
                        # 添加到批量创建列表
                        new_orders.append(Order(**order_data))
                        
                    except Exception as e:
                        error_msg = f"第{index+2}行: {str(e)}"
                        logger.exception(f"处理第 {index+2} 行数据出错")
                        error_rows.append(error_msg)
                
                # 批量创建订单
                if new_orders:
                    Order.objects.bulk_create(new_orders)
                    import_count += len(new_orders)
                    logger.info(f"批量创建了 {len(new_orders)} 个新订单")
                    new_orders = []  # 清空列表，准备下一批
        
        # 清理临时文件
        if delete_after and os.path.exists(file_path):
            os.remove(file_path)
            logger.info(f"清理临时文件: {file_path}")
        
        # 返回导入结果
        result = {
            "success": True,
            "message": f"成功导入 {import_count} 条记录",
            "count": import_count
        }
        
        if error_rows:
            result["errors"] = error_rows
            result["success"] = import_count > 0
            logger.info(f"导入完成，成功: {import_count} 条，错误: {len(error_rows)} 条")
        else:
            logger.info(f"导入完成，全部成功: {import_count} 条")
        
        return result
        
    except Exception as e:
        logger.exception("导入过程中发生错误")
        
        # 清理临时文件
        if delete_after and os.path.exists(file_path):
            os.remove(file_path)
        
        return {
            "success": False, 
            "message": f"导入失败: {str(e)}"
        } 